#include "utils_ipc.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <cstring>
#include "utils_log.h"

namespace El {
namespace Utils {

// === Server 实现 ===

Server::Server(const std::string &name) : pipeName_("/tmp/" + name) {}

Server::~Server()
{
    stop();
}

bool Server::start()
{
    if (running_) {
        return true;
    }

    // 创建命名管道
    unlink(pipeName_.c_str()); // 删除可能存在的旧管道
    if (mkfifo(pipeName_.c_str(), 0666) != 0) {
        EL_ERROR("Error creating named pipe: {}", strerror(errno));
        return false;
    }

    running_ = true;
    serverThread_ = std::make_unique<std::thread>(&Server::serverLoop, this);
    return true;
}

void Server::stop()
{
    if (!running_) {
        return;
    }

    running_ = false;

    // 触发读取管道的阻塞操作退出
    int triggerPipe = open(pipeName_.c_str(), O_WRONLY | O_NONBLOCK);
    if (triggerPipe != -1) {
        close(triggerPipe);
    }

    if (serverThread_ && serverThread_->joinable()) {
        serverThread_->join();
    }

    // 清理
    if (pipeHandle_ != -1) {
        close(pipeHandle_);
        pipeHandle_ = -1;
    }

    unlink(pipeName_.c_str());
}

void Server::serverLoop()
{
    char buffer[4096];

    while (running_) {
        // 打开管道以便读取
        pipeHandle_ = open(pipeName_.c_str(), O_RDONLY);
        if (pipeHandle_ == -1) {
            if (running_) {
                EL_ERROR("Error opening pipe for reading: {}", strerror(errno));
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
            continue;
        }

        // 读取请求
        ssize_t bytesRead = read(pipeHandle_, buffer, sizeof(buffer) - 1);
        close(pipeHandle_);
        pipeHandle_ = -1;

        if (bytesRead <= 0) {
            continue;
        }

        buffer[bytesRead] = '\0';

        // 处理消息
        Message request(buffer);
        Message response;

        if (messageHandler_) {
            messageHandler_(request, response);
        }

        // 打开管道以便写入响应
        pipeHandle_ = open(pipeName_.c_str(), O_WRONLY);
        if (pipeHandle_ != -1) {
            std::string responseStr = response.getData();
            write(pipeHandle_, responseStr.c_str(), responseStr.size());
            close(pipeHandle_);
            pipeHandle_ = -1;
        }
    }
}

// === Client 实现 ===

Client::Client(const std::string &serverName) : serverName_("/tmp/" + serverName) {}

Client::~Client()
{
    disconnect();
}

bool Client::connect()
{
    // 客户端只需要确认管道存在
    struct stat st;
    if (stat(serverName_.c_str(), &st) == -1) {
        EL_ERROR("Server pipe does not exist: {}", serverName_);
        return false;
    }

    if (!S_ISFIFO(st.st_mode)) {
        EL_ERROR("Path exists but is not a pipe: {}", serverName_);
        return false;
    }

    connected_ = true;
    return true;
}

void Client::disconnect()
{
    connected_ = false;
    if (pipeHandle_ != -1) {
        close(pipeHandle_);
        pipeHandle_ = -1;
    }
}

bool Client::sendMessage(const Message &request, Message &response)
{
    if (!connected_) {
        if (!connect()) {
            return false;
        }
    }

    // 打开管道写入请求
    pipeHandle_ = open(serverName_.c_str(), O_WRONLY);
    if (pipeHandle_ == -1) {
        EL_ERROR("Failed to open pipe for writing: {}", strerror(errno));
        disconnect();
        return false;
    }

    // 发送消息
    std::string requestStr = request.getData();
    if (write(pipeHandle_, requestStr.c_str(), requestStr.size()) == -1) {
        EL_ERROR("Failed to write to pipe: {}", strerror(errno));
        close(pipeHandle_);
        pipeHandle_ = -1;
        disconnect();
        return false;
    }

    close(pipeHandle_);

    // 打开管道读取响应
    pipeHandle_ = open(serverName_.c_str(), O_RDONLY);
    if (pipeHandle_ == -1) {
        EL_ERROR("Failed to open pipe for reading: {}", strerror(errno));
        disconnect();
        return false;
    }

    // 读取响应
    char buffer[4096];
    ssize_t bytesRead = read(pipeHandle_, buffer, sizeof(buffer) - 1);
    close(pipeHandle_);
    pipeHandle_ = -1;

    if (bytesRead <= 0) {
        EL_ERROR("Failed to read response or empty response");
        return false;
    }

    buffer[bytesRead] = '\0';
    response.setData(buffer);

    return true;
}

} // namespace Utils
} // namespace El